﻿/* 这个类主要用于获取百度音乐掌门人主页上的一些推荐专辑，所以取名为BaiduAlbums
 * 2010/7/31 By Eleven
 * 现在该类能获取百度推荐和人气专辑还有最新专辑页面的专辑。至于开放专辑(分个人开放和官方开放)，好像html格式稍微有点不一样（desc的位置不太一样还有其他的）。
 * 这个类还带有搜索功能。
 * */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ZMenFM.Network;
using ZMenFM.Network.Spider;
using ZMenFM.Network.Song;
using ZMenFM.Network.Album;
using System.Text.RegularExpressions;

namespace ZMenFM.Network.BaiduAlbums
{
    public static class BaiduAlbums
    {
        private static ZMSpider Spider = new ZMSpider();       //网络爬虫

        #region 一些推荐的专辑
        public static List<AlbumItem> hotAlbums = new List<AlbumItem>();           //人气专辑
        public static List<AlbumItem> recommendAlbums = new List<AlbumItem>();     //百度推荐
        public static List<AlbumItem> newAlbums = new List<AlbumItem>();           //最新专辑
        /// <summary>
        /// 初始化
        /// </summary>
        public static void Initialize()
        {
            ZMSpider.Initialize();
            Spider = new ZMSpider();
            Spider.InitContext(true, "$", true);
            Spider.ClearGetData();
            Spider.ClearPostData();
        }

        /// <summary>
        /// 获得人气专辑
        /// </summary>
        /// <returns></returns>
        public static List<AlbumItem> GetHotAlbums()
        {
            if (hotAlbums.Count > 0)
            {
                return hotAlbums;
            }
            else
            {
                hotAlbums = GetAlbumsFromNet(ZMConstUrl.albumPopularUrl);
            }
            return hotAlbums;
        }

        /// <summary>
        /// 获得百度推荐专辑
        /// </summary>
        /// <returns></returns>
        public static List<AlbumItem> GetRecommendAlbums()
        {
            if (recommendAlbums.Count > 0)
            {
                return recommendAlbums;
            }
            else
            {
                recommendAlbums = GetAlbumsFromNet(ZMConstUrl.albumRecommendUrl);
            }
            return recommendAlbums;
        }

        /// <summary>
        /// 获得最新专辑
        /// </summary>
        /// <returns></returns>
        public static List<AlbumItem> GetNewAlbums()
        {
            if (newAlbums.Count > 0)
            {
                return newAlbums;
            }
            else
            {
                newAlbums = GetAlbumsFromNet(ZMConstUrl.albumNewUrl);
            }
            return newAlbums;
        }

        #region 私有方法
        private static List<AlbumItem> GetAlbumsFromNet(string url)
        {
            List<AlbumItem> list = new List<AlbumItem>();
            string htmlcode = Spider.Get(url,ZMSpiderCodec.VJCD_GB2312);
            string sPattner = @"<!-- loop start -->([\s|\S])*?<!-- loop end -->";
            Regex reg = new Regex(sPattner);
            MatchCollection matches = reg.Matches(htmlcode);
            foreach (Match mc in reg.Matches(htmlcode))
            {
                list.Add(GetAlbumInformationFromCode(mc.ToString().Trim()));
            }
            return list;
        }

        private static AlbumItem GetAlbumInformationFromCode(string code)
        {
            string id, url, name, user, cover, desc;
            string sPattner = @"(?<t>\[\d\d:\d\d\.\d\d\])(?<w>([^\[])+)";
            sPattner = @"<div class=""alist-item"">[\s]*?<table cellspacing=""\d"" cellpadding=""\d"" width=""[\d]*?"">[\s]*?<tr>[\s]*?<td valign=""top"" width=""[\d]*?"" align=""center"">[\s]*?<div class=""aicon""><a href=""(?<url>[\s|\S]*?)"" target=""_blank""><img src=""(?<cover>[\s|\S]*?)"" alt="""" border=""\d"" onload=""[\s|\S]*?"" /></a></div><span class=""[\s|\S]*?"">[\s|\S]*?</span>[\s]*?</td>[\s]*?<td width=""[\d]*?""></td>[\s]*?<td valign=""top"">[\s]*?<div class=""item-title"">[\s]*?<a href=""[\S]*?/(?<id>[\d]*?)\.html"" title=""(?<title>[\s|\S]*?)"" target=""_blank"">[\s|\S]*?</a>[\s|\S]*?(<a target=""_blank"" href=""[\s|\S]*?""><img src=""[\s|\S]*?"" width=""[\d]*?"" height=""[\d]*?"" border=""[\d]*?"" alt="""" style=""[\s|\S]*?"" /></a>[\s]*?)*?</div>[\s]*?<div class=""item-zmr"">[\s]*?掌门人：<a href=""[\S]*?"" title=""(?<user>[\S]*?)"" target=""_blank"">[\S]*?</a><br>[\s]*?分类：([\s|\S]*?)</div>[\s]*?<div class=""item-desc"">(?<desc>[\S|\s]*?)[\s]*?</div>[\s]*?<div class=""item-gc"">[\s|\S]*?</div>[\s]*?<div class=""item-ll"">[\s|\S]*?[\s]*?</div>[\s]*?</td>[\s]*?</tr>[\s]*?</table>[\s]*?</div>";
            Regex reg = new Regex(sPattner);
            Match match = reg.Match(code);
            url = match.Groups["url"].ToString().Trim();
            cover = match.Groups["cover"].ToString().Trim();
            name = match.Groups["title"].ToString().Trim();
            user = match.Groups["user"].ToString().Trim();
            desc = match.Groups["desc"].ToString().Trim();
            id = match.Groups["id"].ToString().Trim();
            AlbumItem albumItem = new AlbumItem(id, url, cover, name, user, desc);
            return albumItem;
        }

        private static string ToChinese(string utf16String)
        {
            //转换后返回所转换
            string[] splitString = new string[1];
            splitString[0] = @"\u";
            string[] utf16Strings = utf16String.Split(splitString, StringSplitOptions.RemoveEmptyEntries);
            StringBuilder returnString = new StringBuilder();
            foreach (string ss in utf16Strings)
            {
                //ss是4个字符构成的一个字符编码，占用4个编码；
                //string->byte[]->string
                byte[] codes = new byte[2];
                int code1, code2;
                code1 = Convert.ToInt32(ss.Substring(0, 2), 16);
                code2 = Convert.ToInt32(ss.Substring(2), 16);
                codes[0] = (byte)code2;
                codes[1] = (byte)code1;
                string getString = Encoding.Unicode.GetString(codes);
                returnString.Append(getString);
            }
            return returnString.ToString();
        }
        #endregion
        #endregion

        #region 获得搜索的专辑
        private static string baseurl = ZMConstUrl.baseUrl; //因为html中的路径是相对路径，创建album的时候要加上基路径才行
        private static string previousPage = "";                                   //上一页的网址
        private static string nextPage = "";                                       //下一页的网址

        /// <summary>
        /// 获得搜索页第一页的专辑列表
        /// </summary>
        /// <param name="keywords"></param>
        /// <returns></returns>
        public static List<AlbumItem> GetAlbumsByKeywords(string keywords)
        {
            List<AlbumItem> list = new List<AlbumItem>();
            string url = ZMConstUrl.searchUrl+"?word=" + keywords;
            list = GetAlbum(url);
            return list;
        }

        /// <summary>
        /// 获得下一页的专辑列表
        /// </summary>
        /// <returns>如果返回空则已经到最后一页</returns>
        public static List<AlbumItem> GetNextPageAlbums()
        {
            if (nextPage == "") //如果没有下一页了则返回空
            {
                return null;
            }
            List<AlbumItem> list = new List<AlbumItem>();
            list = GetAlbum(nextPage);
            return list;
        }

        /// <summary>
        /// 获得上一页的专辑列表
        /// </summary>
        /// <returns>如果返回空则已经到达第一页</returns>
        public static List<AlbumItem> GetPreviouPageAlbums()
        {
            if (previousPage == "") //如果没有上一页了则返回空
            {
                return null;
            }
            List<AlbumItem> list = new List<AlbumItem>();
            list = GetAlbum(previousPage);
            return list;
        }

        #region 私有函数
        //私有 // 专辑搜索页面通过分析html获得专辑列表
        private static List<AlbumItem> GetAlbum(string pageurl)
        {

            string code = Spider.Get(pageurl, ZMSpiderCodec.VJCD_GB2312);
            List<AlbumItem> list = new List<AlbumItem>();
            //找出专辑
            string sPattner = @"<div>[\s]*?<table cellpadding=""0"" cellspacing=""0"" border=""0"" width=""100%"" class=""alrs"">[\s]*?<tr>[\s]*?<td rowspan=""[\d]*?"" width=""[\S]*?"" valign=""top"" class=""alpic""><a href=""[\S]*?/(?<id>[\d]*?).html"" target=""_blank""><img src=""(?<cover>[\S]*?)"" onload=""([\S]*?)"" /></a><br/></td>[\s]*?<td class=""altopic"" width=""[\s|\S]*?""><a href=""(?<url>[\s|\S]*?)"" title=""(?<name>[\s|\S]*?)"" target=""_blank"">[\s|\S]*?</a></td>[\s]*?<td class=""time"" align=""[\s|\S]*?"">(?<time>[\S]*?)</td>[\s]*?</tr>[\s]*?<tr>[\s]*?<td colspan=""2"">掌门人：<a href=""[\S]*?"" target=""_blank"">(?<user>[\S|\s]*?)</a> 分类：([\S|\s]*?)[\s]*?<tr>[\s]*?<td colspan=""2"">(?<desc>[\S|\s]*?)<a href=""[\S]*?"" target=""_blank"">详情>></a></td>[\s]*?</tr>[\s]*?<tr>(?<songs>[\s|\S]*?)</tr>[\s]*?<tr>[\s]*?<td colspan=""2"" class=""g"">[\S|\s]*?</td>[\s]*?</tr>[\s]*?</table>[\s]*?</div>";
            Regex reg = new Regex(sPattner);
            MatchCollection matches = reg.Matches(code);
            foreach (Match i in matches)
            {
                string id, url, name, user, cover, desc;
                id = i.Groups["id"].ToString().Trim();
                url = baseurl + i.Groups["url"].ToString().Trim();
                name = i.Groups["name"].ToString().Trim();
                cover = i.Groups["cover"].ToString().Trim();
                user = i.Groups["user"].ToString().Trim();
                desc = i.Groups["desc"].ToString().Trim();
                AlbumItem album = new AlbumItem(id, url, cover, name, user, desc);
                list.Add(album);
            }
            //设置previouspage和nextpage
            string patternnext = @"<nobr><a href=""(?<nextpage>[^<]*?)""><font size=3>下一页</font></a></nobr>";
            Regex regexnext = new Regex(patternnext);
            Match match = regexnext.Match(code);
            string nexturl = match.Groups["nextpage"].ToString().Trim();
            if (nexturl != "")
            {
                nexturl = ZMConstUrl.searchUrl + nexturl;
            }
            string patternprevious = @"<nobr><a href=""(?<previouspage>[^<]*?)""><font size=3>上一页</font></a></nobr>";
            Regex regexprevious = new Regex(patternprevious);
            Match match1 = regexprevious.Match(code);
            string previousurl = match1.Groups["previouspage"].ToString().Trim();
            if (previousurl != "")
            {
                previousurl = ZMConstUrl.searchUrl + previousurl;
            }
            previousPage = previousurl;
            nextPage = nexturl;
            return list;
        }
        #endregion
        #endregion
    }
}
